#include "stdafx.h"
#include "MeshSort.h"

void MeshSort::UpdateTriangle(const vector<MeshData>& vData)
{

	m_pntMin[0] = m_pntMin[1] = m_pntMin[2] = 1e+10;
	m_pntMax[0] = m_pntMax[1] = m_pntMax[2] = -1e+10;

	m_vTriangles.clear();
	for (auto data : vData)
	{
		vector<Point_3> vPnts;
		vector<unsigned int> vTri;
		data.ToData(vPnts, vTri);
		for (Point_3 pnt : vPnts)
		{
			for (int i=0; i<3; ++i)
			{
				m_pntMin[i] = min(m_pntMin[i], pnt[i]);
				m_pntMax[i] = max(m_pntMax[i], pnt[i]);
			}
		}
		for (int i = 0; i < vTri.size() / 3; ++i)
		{
			m_vTriangles.push_back(CGAL_Triangle(vPnts[vTri[3 * i + 0]], vPnts[vTri[3 * i + 1]], vPnts[vTri[3 * i + 2]]));
		}
	}
	m_pTree = shared_ptr<AABBTree>(new AABBTree(m_vTriangles.begin(), m_vTriangles.end()));
	m_pTree->build();
}

int MeshSort::GetHeight(double& z, double x, double y) const
{

	typedef K::Ray_3 Ray;
	typedef boost::optional< AABBTree::Intersection_and_primitive_id<Ray>::Type > Ray_intersection;
	int iRet = 1;
	Point_3 pntFrom, pntTo;
	pntFrom = Point_3(x, y, m_pntMin[2] - 100);
	pntTo = Point_3(x, y, m_pntMax[2] + 100);
	Ray ray_query(pntFrom, pntTo);
	Ray_intersection intersection = m_pTree->any_intersection(ray_query);
	if (intersection)
	{
		if (boost::get<Point_3>(&(intersection->first)))
		{
			iRet = 0;
			Point_3* pPnt = boost::get<Point_3>(&(intersection->first));
			z = (double)pPnt->z();
		}
	}
	return iRet;
}
void MeshSort::Save(CFileSaveData& fp)
{
	fp.Write((int)(m_vTriangles.size()));
	for (CGAL_Triangle& tri : m_vTriangles)
	{
		KBase::Point_3 pnt[3] = { tri[0] ,tri[1] ,tri[2] };

		fp.Write(pnt[0]);
		fp.Write(pnt[1]);
		fp.Write(pnt[2]);
	}

	fp.Write((int)(m_pTree->m_primitives.size()));
	for (int i = 0; i < m_pTree->m_primitives.size(); ++i)
	{
		int inx = m_pTree->m_primitives[i].id() - m_vTriangles.begin();
		fp.Write(inx);
	}
	const AABBTree::Node* pNodeRoot = m_pTree->root_node();

	int iNodeSize = m_pTree->m_primitives.size() - 1;
	fp.Write(iNodeSize);
	for (int i = 0; i < iNodeSize; ++i)
	{
		const AABBTree::Node* pNode = pNodeRoot + i;
		{
			fp.Write(pNode->bbox());
			int iType = 0;
			{
				int iOffset = ((const AABBTree::Node*)pNode->m_p_left_child - pNodeRoot);
				if (iOffset >= 0 && iOffset < iNodeSize)
				{
					iType = 0;
				}
				else
				{
					iOffset = ((Primitive*)pNode->m_p_left_child - (Primitive*)(m_pTree->m_primitives.data()));
					iType = 1;
				}
				fp.Write(iType);
				fp.Write(iOffset);
			}
			{
				int iOffset = ((const AABBTree::Node*)pNode->m_p_right_child - pNodeRoot);
				if (iOffset >= 0 && iOffset < iNodeSize)
				{
					iType = 0;
				}
				else
				{
					iOffset = ((Primitive*)pNode->m_p_right_child - (Primitive*)(m_pTree->m_primitives.data()));
					iType = 1;
				}
				fp.Write(iType);
				fp.Write(iOffset);
			}
		}

	}
}

void MeshSort::Save(string sFileName)
{
	CFileSaveData fp(sFileName);
	Save(fp);
}

void MeshSort::Load(CFileLoadData& fp)
{
	int iSize;
	fp.Read(iSize);
	m_vTriangles.resize(iSize);
	for (CGAL_Triangle& tri : m_vTriangles)
	{
		KBase::Point_3 pnt[3];
		fp.Read(pnt[0]);		fp.Read(pnt[1]);		fp.Read(pnt[2]);
		tri = CGAL_Triangle(pnt[0], pnt[1], pnt[2]);
	}

	m_pTree = shared_ptr<AABBTree>(new AABBTree());
	fp.Read(iSize);
	vector<int> vInx(iSize);
	for (int i = 0; i < iSize; ++i)
	{
		int inx;
		fp.Read(inx);
		vInx[i] = inx;
	}

	m_pTree->m_primitives.clear();
	for (int i = 0; i < iSize; ++i)
	{
		m_pTree->m_primitives.push_back(AABBTree::Primitive(m_vTriangles.begin() + vInx[i]));
	}
	m_pTree->m_need_build = false;


	fp.Read(iSize);
	AABBTree::Node* pNodeRoot = new AABBTree::Node[iSize];
	for (int i = 0; i < iSize; ++i)
	{
		AABBTree::Node* pNode = pNodeRoot + i;
		fp.Read(pNode->m_bbox);
		{
			int iOffset;
			int iType = 0;
			fp.Read(iType);
			fp.Read(iOffset);
			if (iType == 0)
			{
				pNode->m_p_left_child = (void*)(pNodeRoot + iOffset);
			}
			else
			{
				pNode->m_p_left_child = (void*)(m_pTree->m_primitives.data() + iOffset);
			}

		}

		{
			int iOffset;
			int iType = 0;
			fp.Read(iType);
			fp.Read(iOffset);
			if (iType == 0)
			{
				pNode->m_p_right_child = (void*)(pNodeRoot + iOffset);
			}
			else
			{
				pNode->m_p_right_child = (void*)(m_pTree->m_primitives.data() + iOffset);
			}

		}
	}
	m_pTree->m_p_root_node = pNodeRoot;

}

void MeshSort::Load(string sFileName)
{
	CFileLoadData fp(sFileName);
	Load(fp);
}
